#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <chrono>
#include <ctime>
#include <condition_variable>

void Print(int n, int i)
{
    for (; i < n; ++i)
        std::cout << std::this_thread::get_id() << ": " << i << std::endl;

    std::cout << std::endl;
}

void Print(int n, int &rx, std::mutex &mu)
{
    mu.lock();
    for (int i = 0; i < n; i++)
        ++rx;
    mu.unlock();
}

void testThread()
{
    std::thread t1(static_cast<void (*)(int, int)>(Print), 10, 0);
    std::thread t2(static_cast<void (*)(int, int)>(Print), 20, 10);

    t1.join();
    t2.join();

    std::cout << std::this_thread::get_id() << std::endl;
}

void testChrono()
{
    using namespace std;
    using namespace std::chrono;

    // cout << "countdown: \n";
    // for (int i = 10; i > 0; --i)
    // {
    //     cout << i << endl;
    //     std::this_thread::sleep_for(std::chrono::seconds(1));
    // }
    // cout << "List off!\n";
    duration<int, std::ratio<60 * 60 * 24>> one_day(1);
    system_clock::time_point today = system_clock::now();
    system_clock::time_point tomorrow = today + one_day;
    time_t tt;
    tt = system_clock::to_time_t(today);
    cout << "today is :" << ctime(&tt);
    tt = system_clock::to_time_t(tomorrow);
    cout << "tomorrow will be :" << ctime(&tt);
}

void test1()
{
    int x = 0;
    std::mutex mu;
    std::thread t1(static_cast<void (*)(int, int &, std::mutex &)>(Print), 1000000, std::ref(x), std::ref(mu));
    std::thread t2(static_cast<void (*)(int, int &, std::mutex &)>(Print), 2000000, std::ref(x), std::ref(mu));

    t1.join();
    t2.join();
    std::cout << "x: " << x << std::endl;
}
std::timed_mutex mtx;
void fireworks(int i)
{
    // mtx.lock();
    while (!mtx.try_lock_for(std::chrono::milliseconds(1000)))
    {
        std::cout << "-";
    }
    std::cout << i;
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    std::cout << "*\n";
    mtx.unlock();
}
void test2()
{
    std::thread threads[2];
    for (int i = 0; i < 2; ++i)
        threads[i] = std::thread(fireworks, i);
    for (auto &th : threads)
        th.join();
}
std::mutex mtx1;
void print_thread_id(int id)
{
    // 加不加adopt_lock在这个函数里是一样的，adopt_lock是为了防止死锁提供的
    std::lock_guard<std::mutex> lg(mtx1, std::adopt_lock);
    std::cout << "thread # " << id << '\n';
}

void test3()
{
    std::thread threads[10];
    for (int i = 0; i < 10; ++i)
        threads[i] = std::thread(print_thread_id, i + 1);
    for (std::thread &th : threads)
        th.join();
}
#define print(x) (std::cout << x << std::endl)
std::mutex foo, bar;
void task_a()
{
    // std::lock(foo, bar);
    // print("task_a");
    // foo.unlock();
    // bar.unlock();
    foo.lock();
    print("task_a");
    bar.lock();
    foo.unlock();
    bar.unlock();
}

void task_b()
{
    // std::lock(foo, bar);
    // print("task_b");
    // foo.unlock();
    // bar.unlock();
    // 全部加锁成功返回-1，否则返回的值代表第几个锁没有加成功，下标从0开始
    int x = std::try_lock(foo, bar);
    if (x == -1)
    {
        print("task_b");
        foo.unlock();
        bar.unlock();
    }
    else
    {
        print(x);
        print((x ? "foo" : "bar"));
    }
}
using namespace std::string_literals;
void test4()
{
    // foo.lock();
    // std::thread t1(task_a);
    // std::thread t2(task_b);
    // print("1.xxxxxxxxxxxx");
    // bar.lock();
    // foo.unlock();
    // print("2.xxxxxxxxxxxx");

    // bar.unlock();

    std::thread t1(task_a);
    std::thread t2(task_b);
    t1.join();
    t2.join();
    auto str1111 = "hello"s;
}

int winner;
void set_flag(int x) { winner = x; }
std::once_flag winner_flag;
void wait1000ms(int fd)
{
    for (int i = 0; i < 1000; ++i)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
    std::call_once(winner_flag, set_flag, fd);
}
void test5()
{
    std::thread threads[10];
    for (int i = 0; i < 10; ++i)
    {
        threads[i] = std::thread(wait1000ms, i + 1);
    }
    for (auto &th : threads)
        th.join();
    std::cout << winner << std::endl;
}
std::condition_variable cv;
bool ready = false;

void print_id(int id)
{
    std::unique_lock<std::mutex> lock(mtx1);

    while (!ready)
        cv.wait(lock);
    printf("thread: %d\n", id);
}

void go()
{
    std::unique_lock<std::mutex> lock(mtx1);
    ready = true;
    cv.notify_all();
}

void test6()
{
    std::thread threads[10];
    for (int i = 0; i < 10; ++i)
    {
        threads[i] = std::thread(print_id, i + 1);
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    go();

    for (auto &th : threads)
        th.join();
}

int main()
{
    // testThread();
    // testChrono();
    // test1();
    // test2();
    // test3();
    // test4();
    // test5();
    test6();
    return 0;
}